package com.segersten.kalaha

import java.util.logging.Logger;

import com.restfb.Connection
import com.restfb.FacebookClient
import com.restfb.DefaultFacebookClient
import com.restfb.types.User
import com.restfb.types.NamedFacebookType
import com.restfb.exception.FacebookOAuthException
import com.segersten.kalaha.Player
import com.segersten.kalaha.PlayerCache
import com.google.appengine.repackaged.com.google.common.util.Base64
import com.google.appengine.repackaged.com.google.common.util.Base64DecoderException
import com.restfb.DefaultJsonMapper
import com.segersten.kalaha.util.authentication.SignedRequest

/**
 * Controller integrating with Facebook
 */
class FacebookController {

	private static Logger LOG = Logger.getLogger(getClass().getCanonicalName());

	def facebookKeys

	static defaultAction = "authent";

	def authent = {
		LOG.info("LOGIN - authent")
		params.each { key, value -> LOG.info "authent authentgame params[${key}] == ${value}" }
		def redirectURI = "http://${facebookKeys.callbackDomain}/facebook/callback"
		redirect(url: "https://www.facebook.com/dialog/oauth?client_id=${facebookKeys.clientCode}&redirect_uri=${redirectURI}")
	}

	def authentgame = {
		//TODO error_reason!!!
		params.each { key, value -> LOG.info "authentgame params[${key}] == ${value}" }
		LOG.info("LOGIN - authentgame")

		if (params.signed_request) {
			def res = params.signed_request.tokenize("\\.")[1]
			def data = base64decode(res)
			def sr = getSignedRequest(data)
			LOG.info "sr.userId == ${sr.userId}"
			LOG.info "sr.oathToken == ${sr.oauthToken}"
			if (sr.userId!=null) {
				def redirectURI = "http://${facebookKeys.callbackDomain}/start/index"
				redirect(url: "https://www.facebook.com/dialog/oauth?client_id=${facebookKeys.clientCode}&redirect_uri=${redirectURI}")
				return
			}
		}
		//render(text:"goto view")
		// return to view that redirect to top frame for further login in (eventually 'firstauthentgame')
		[url: "http://${facebookKeys.callbackDomain}/facebook/firstauthentgame"]
	}

	def firstauthentgame = {
		params.each { key, value -> LOG.info "firstauthentgame params[${key}] == ${value}" }
		LOG.info("LOGIN - firstauthentgame")


		def redirectURI = "http://${facebookKeys.callbackDomain}/facebook/redirecter"
		redirect(url: "https://www.facebook.com/dialog/oauth?client_id=${facebookKeys.clientCode}&redirect_uri=${redirectURI}")
	}

	def redirecter = {
		params.each { key, value -> LOG.info "redirecter params[${key}] == ${value}" }
		redirect(url:"http://${facebookKeys.facebookDomainName}")
	}
	
	def callback = {
		// Request an access token by fetching url with given code.
		def redirectURI = "http://${facebookKeys.callbackDomain}/facebook/callback"
		def rootUrl = "https://graph.facebook.com/oauth/access_token?client_id=${facebookKeys.clientCode}&client_secret=${facebookKeys.clientSecret}"
		String accessTokenURL = rootUrl + "&redirect_uri=${redirectURI}&code=${params.code.encodeAsURL()}"
		String result = new URL(accessTokenURL).getText()
		// Access token is first key=value pairs value.
		String accessToken = result.tokenize("&")[0].tokenize("=")[1]

		chain(action:getFriends,params:[accessToken:accessToken])
	}

	def getFriends = {
		def accessToken = null
		if (params.accessToken) {
			accessToken = params.accessToken
		} else if (params.sessionId) {
			PlayerCache pc = new PlayerCache()
			Player player = pc.getBySessionId(params.sessionId)
			if (!player) {
				render(text:"Error:getFriends - Failed to get player!")
				return
			}
			accessToken = player.accessToken
		}
		if (!accessToken || accessToken.size() == 0 ) {
			render(view: 'error', model: [result : "No access token provided as expected.",
						accessToken: "", error: ""])
		}
		// Use a facebook client to request current logged in user friends.
		FacebookClient fb = new DefaultFacebookClient(accessToken)
		try {
			User me = fb.fetchObject("me", User.class)
			Connection friends = fb.fetchConnection("me/friends", NamedFacebookType.class)
			render(view: 'callback',
					model: [me : me, friends: friends.data, accessToken: accessToken])
		} catch(FacebookOAuthException e) {
			render(view: 'error', model: [accessToken: accessToken, error: e])
		}
	}


	// TODO break out - code duplicated from StartController
	def getSignedRequest = { String json ->
		DefaultJsonMapper mapper = new DefaultJsonMapper()
		SignedRequest sr = mapper.toJavaObject(json, SignedRequest.class)
		sr
	}

	// TODO break out - code duplicated from StartController
	def base64decode = { String data ->
		try {
			new String(Base64.decode(data))
		} catch(Base64DecoderException e) {
			"error"
		}
	}
}